package simpledb.planner;

import simpledb.tx.Transaction;
import simpledb.parse.*;
import simpledb.query.*;

/**
 * The object that executes SQL statements.
 * @author sciore
 */
public class Planner {
   private QueryPlanner oplanner;
   private QueryPlanner qplanner;
   private UpdatePlanner uplanner;
   private static Transaction lastTx;
   private static Boolean optimized;
   public static TempTableMgr ttm;
   
   public Planner(QueryPlanner oplanner, QueryPlanner qplanner, UpdatePlanner uplanner) {
	  this.oplanner = oplanner;
      this.qplanner = qplanner;
      this.uplanner = uplanner;
      Planner.optimized = false;
      Planner.ttm = new TempTableMgr();
   }
   
   /**
    * Creates a plan for an SQL select statement, using the supplied planner.
    * @param qry the SQL query string
    * @param tx the transaction
    * @return the scan corresponding to the query plan
    */
   public Plan createQueryPlan(String qry, Transaction tx) {
	      // Modified by Kenneth J. Loomis
	   	  // Finalized on December 6, 2011
	   	  //String qryArray[];
	   	  PreParser preP = new PreParser( qry );
	      Plan p;

	      //Step 1: Determine if a query should be optimized	      
	      if ( tx != Planner.lastTx )
	      {
	    	  Planner.lastTx = tx; 
	    	  qry = preP.optimized( );
	    	  Planner.optimized = preP.isOptimized();
	      }
	      qry = preP.parse( this, tx );
	      	//qryArray = 
	      	//qry = qryArray[0];  
	      
	      // step 2: Determine which planner to use
	      if ( Planner.optimized )
	      {
		      Parser parser = new Parser( qry, tx );
		      QueryData data = parser.query();
	    	  p = oplanner.createPlan(data, tx);
	      }
	      else
	      {
	    	  Parser parser = new Parser( qry, tx );
		      QueryData data = parser.query();
	    	  p = qplanner.createPlan(data, tx);
	      }
	      return p;
	   }   
   /* Original Unmodified version
   public Plan createQueryPlan(String qry, Transaction tx) {
      Parser parser = new Parser(qry);
      QueryData data = parser.query();
      return qplanner.createPlan(data, tx);
   }
*/ 
  
   public String addTempTable ( Plan p)
   {
	   return Planner.ttm.Insert( p );
   }
   
   public Plan getTempTablePlan ( String s)
   {
	   return Planner.ttm.GetPlan(s);
   }
   
   /**
    * Executes an SQL insert, delete, modify, or
    * create statement.
    * The method dispatches to the appropriate method of the
    * supplied update planner,
    * depending on what the parser returns.
    * @param cmd the SQL update string
    * @param tx the transaction
    * @return an integer denoting the number of affected records
    */
   public int executeUpdate(String cmd, Transaction tx) {
      Parser parser = new Parser(cmd, tx);
      Object obj = parser.updateCmd();
      if (obj instanceof InsertData)
         return uplanner.executeInsert((InsertData)obj, tx);
      else if (obj instanceof DeleteData)
         return uplanner.executeDelete((DeleteData)obj, tx);
      else if (obj instanceof ModifyData)
         return uplanner.executeModify((ModifyData)obj, tx);
      else if (obj instanceof CreateTableData)
         return uplanner.executeCreateTable((CreateTableData)obj, tx);
      else if (obj instanceof CreateViewData)
         return uplanner.executeCreateView((CreateViewData)obj, tx);
      else if (obj instanceof CreateIndexData)
         return uplanner.executeCreateIndex((CreateIndexData)obj, tx);
      else
         return 0;
   }
}
